﻿/*
 * Creado por SharpDevelop.
 * Usuario: jfacorro
 * Fecha: 22/05/2010
 * Hora: 3:38
 * 
 * Para cambiar esta plantilla use Herramientas | Opciones | Codificación | Editar Encabezados Estándar
 */
using System;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;

using soundtouch;
using WiimoteLib;

namespace TimeMaker
{
	/// <summary>
	/// Description of MainForm.
	/// </summary>
	public partial class MainForm : Form
	{		
		const float TAP_THRESHOLD_VALUE = 3.0f;

		/// <summary>
		/// SetControlPropertyThreadSafeDelegate
		/// </summary>
		private delegate void SetControlPropertyThreadSafeDelegate(Control control, string propertyName, object propertyValue);
	
		/// <summary>
		/// Bpm Reader used to calculate the bpm
		/// based on taps
		/// </summary>
		private BpmReader reader;
		
		/// <summary>
		/// Wiimote instance
		/// </summary>
		private Wiimote wiimote;
		
		/// <summary>
		/// Area were the graphic will be drawn
		/// </summary>
		private Bitmap drawArea;
		
		/// <summary>
		/// Object that contains both values and the drawing logic
		/// </summary>
		private FunctionGraph functionGraph;
		
		/// <summary>
		/// Loads the song and calculates its BPM
		/// </summary>
		private SongManager songManager;
		
		/// <summary>
		/// Used for tapping detection
		/// </summary>
		private bool tap = false;

		public MainForm()
		{
			//
			// The InitializeComponent() call is required for Windows Forms designer support.
			//
			InitializeComponent();

			this.songManager = new SongManager();
			this.reader = new BpmReader();
			this.wiimote = new Wiimote();			
			this.wiimote.WiimoteChanged += Wiimote_Changed;
			
			this.Load += new EventHandler(MainForm_Load);
			
			this.tmrTicker.Enabled = true;
		}

		void MainForm_Load(object sender, EventArgs e)
		{
			this.InitializeDrawArea();
			
			this.functionGraph = new FunctionGraph(this.drawArea);

			this.DoubleBuffered = true;
		}
		
        private void InitializeDrawArea()
        {
            this.drawArea = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height / 2, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            
            Graphics g = Graphics.FromImage(this.drawArea);
            
            g.Clear(Color.Black);
        }
        
		protected override void OnPaint(PaintEventArgs e)
		{
			this.functionGraph.Update();
			
			e.Graphics.DrawImage(this.drawArea, new System.Drawing.Point(0, this.ClientRectangle.Height / 2));
			
			base.OnPaint(e);
		}
		
		private void ConnectWiimote()
		{
			try
			{
				wiimote.Connect();
				wiimote.SetReportType(InputReport.IRAccel, true);
				wiimote.SetLEDs(true, false, false, false);
			}
			catch {}
		}
		
		private void Wiimote_Changed(object sender, WiimoteChangedEventArgs args)
		{
			WiimoteState ws = args.WiimoteState;
			
			this.DetectUserBpm(ws.AccelState.Values.Z);
		}
		
		private void DetectUserBpm(float zCoord)
		{
			if(!float.IsInfinity(zCoord))
			{
				this.functionGraph.Add(zCoord);

				if(this.tap && zCoord > TAP_THRESHOLD_VALUE && this.functionGraph.Slope() == 0)
				{
					this.reader.tap();
					
					float ratio = this.reader.GetBpm() / this.songManager.Bpm;
					
					this.SetControlPropertyThreadSafe(this.lblBPMRatioValue, "Text", ratio.ToString());
					this.SetControlPropertyThreadSafe(this.lblBPMValue, "Text", this.reader.GetBpm().ToString());
					
					this.tap = false;
				}
				else if(!this.tap && zCoord < TAP_THRESHOLD_VALUE)
				{
					this.tap = true;
				}
			}
		}

		public void SetControlPropertyThreadSafe(Control control, string propertyName, object propertyValue)
		{
			if (control.InvokeRequired)
			{
				control.Invoke(new SetControlPropertyThreadSafeDelegate(SetControlPropertyThreadSafe), new object[] { control, propertyName, propertyValue });
			}
			else
			{
				control.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, control, new object[] { propertyValue });
			}
		}
		
		/// <summary>
		/// Loads a song and starts to play it
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected void BtnLoadSong_Click(object sender, EventArgs e)
		{
			FileDialog fileDialog = new OpenFileDialog();
			fileDialog.Filter = "MP3 files(*.mp3)|*.mp3";
			DialogResult result = fileDialog.ShowDialog();

			if(result == DialogResult.OK)
			{
				this.songManager.LoadSong(fileDialog.FileName);
				this.songManager.Play();
				this.ConnectWiimote();
				this.SetControlPropertyThreadSafe(this.lblBPMSongValue, "Text", this.songManager.Bpm.ToString());
			}
		}
		
		protected void TmrTicker_Tick(object sender, EventArgs e)
		{
			// Call Invalidate() to force Paint() invocation
			this.Invalidate();
		}
	}
}
